home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / udp.c < prev    next >
C/C++ Source or Header  |  1992-06-18  |  7KB  |  318 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "internet.h"
  7.  
  8.  
  9. static struct udp_cb *lookup_udp();
  10. static int16 hash_udp();
  11. /* Hash table for UDP structures */
  12. struct udp_cb *udps[NUDP] = { NULLUDP} ;
  13. struct udp_stat udp_stat;    /* Statistics */
  14.  
  15. /* Create a UDP control block for lsocket, so that we can queue
  16.  * incoming datagrams.
  17.  */
  18. int
  19. open_udp(lsocket,r_upcall)
  20. struct socket *lsocket;
  21. void (*r_upcall)();
  22. {
  23.     register struct udp_cb *up;
  24.     /* struct udp_cb *lookup_udp();  */
  25.     int16 hval,hash_udp();
  26.  
  27.     if((up = lookup_udp(lsocket)) != NULLUDP)
  28.         return 0;    /* Already exists */
  29.     if((up = (struct udp_cb *)malloc(sizeof (struct udp_cb))) == NULLUDP){
  30.         net_error = NO_SPACE;
  31.         return -1;
  32.     }
  33.     up->rcvq = NULLBUF;
  34.     up->rcvcnt = 0;
  35.     up->socket.address = lsocket->address;
  36.     up->socket.port = lsocket->port;
  37.     up->r_upcall = r_upcall;
  38.  
  39.     hval = hash_udp(lsocket);
  40.     up->next = udps[hval];
  41.     up->prev = NULLUDP;
  42.     if(up->next != NULLUDP)
  43.         up->next->prev = up;
  44.     udps[hval] = up;
  45.     return 0;
  46. }
  47.  
  48. /* Send a UDP datagram */
  49. int
  50. send_udp(lsocket,fsocket,tos,ttl,data,length,id,df)
  51. struct socket *lsocket;        /* Source socket */
  52. struct socket *fsocket;        /* Destination socket */
  53. char tos;            /* Type-of-service for IP */
  54. char ttl;            /* Time-to-live for IP */
  55. struct mbuf *data;        /* Data field, if any */
  56. int16 length;            /* Length of data field */
  57. int16 id;            /* Optional ID field for IP */
  58. char df;            /* Don't Fragment flag for IP */
  59. {
  60.     struct mbuf *htonudp(),*bp;
  61.     struct pseudo_header ph;
  62.     struct udp udp;
  63.  
  64.     length = UDPHDR;
  65.     if(data != NULLBUF)
  66.         length += len_mbuf(data);
  67.  
  68.     udp.source = lsocket->port;
  69.     udp.dest = fsocket->port;
  70.     udp.length = length;
  71.  
  72.     /* Create IP pseudo-header, compute checksum and send it */
  73.     ph.length = length;
  74.     ph.source = lsocket->address;
  75.     ph.dest = fsocket->address;
  76.     ph.protocol = UDP_PTCL;
  77.  
  78.     if((bp = htonudp(&udp,data,&ph)) == NULLBUF){
  79.         net_error = NO_SPACE;
  80.         free_p(data);
  81.         return 0;
  82.     }
  83.     udp_stat.sent++;
  84.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  85.     return length;
  86. }
  87.  
  88. /* Accept a waiting datagram, if available. Returns length of datagram */
  89. int
  90. recv_udp(lsocket,fsocket,bp)
  91. struct socket *lsocket;        /* Local socket to receive on */
  92. struct socket *fsocket;        /* Place to stash incoming socket */
  93. struct mbuf **bp;            /* Place to stash data packet */
  94. {
  95.     /* struct udp_cb *lookup_udp(); */
  96.     register struct udp_cb *up;
  97.     struct socket *sp;
  98.     struct mbuf *buf;
  99.     int16 length;
  100.  
  101.     up = lookup_udp(lsocket);
  102.     if(up == NULLUDP){
  103.         net_error = NO_CONN;
  104.         return -1;
  105.     }
  106.     if(up->rcvcnt == 0){
  107.         net_error = WOULDBLK;
  108.         return -1;
  109.     }
  110.     buf = dequeue(&up->rcvq);
  111.     up->rcvcnt--;
  112.  
  113.     sp = (struct socket *)buf->data;
  114.     /* Fill in the user's foreign socket structure, if given */
  115.     if(fsocket != NULLSOCK){
  116.         fsocket->address = sp->address;
  117.         fsocket->port = sp->port;
  118.     }
  119.     /* Strip socket header and hand data to user */
  120.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  121.     length = len_mbuf(buf);
  122.     if(bp != (struct mbuf **)NULL)
  123.         *bp = buf;
  124.     else
  125.         free_p(buf);
  126.     return length;
  127. }
  128. /* Delete a UDP control block */
  129. int
  130. del_udp(lsocket)
  131. struct socket *lsocket;
  132. {
  133.     register struct udp_cb *up;
  134. /*    struct udp_cb *lookup_udp();  */
  135.     struct mbuf *bp;
  136.     int16 hval,hash_udp();
  137.  
  138.     if((up = lookup_udp(lsocket)) == NULLUDP){
  139.         net_error = INVALID;
  140.         return -1;
  141.     }        
  142.     /* Get rid of any pending packets */
  143.     while(up->rcvcnt != 0){
  144.         bp = up->rcvq;
  145.         up->rcvq = up->rcvq->anext;
  146.         free_p(bp);
  147.         up->rcvcnt--;
  148.     }
  149.     hval = hash_udp(&up->socket);
  150.     if(udps[hval] == up){
  151.         /* First on list */
  152.         udps[hval] = up->next;
  153.         if (up->next != NULLUDP)
  154.             up->next->prev = NULLUDP;
  155.     } else {
  156.         up->prev->next = up->next;
  157.         if (up->next != NULLUDP)
  158.             up->next->prev = up->prev;
  159.     }
  160.     free((char *)up);
  161.     return 0;
  162. }
  163. /* Process an incoming UDP datagram */
  164. /*ARGSUSED*/
  165. void
  166. udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  167. struct mbuf *bp;    /* UDP header and data */
  168. char protocol;        /* Should always be 17 */
  169. int32 source;        /* Source IP address */
  170. int32 dest;        /* Dest IP address */
  171. char tos;
  172. int16 length;
  173. char rxbroadcast;    /* The only protocol that accepts 'em */
  174. {
  175.     struct pseudo_header ph;
  176.     struct udp udp;
  177.     struct udp_cb *up /* ,*lookup_udp()   */ ;
  178.     struct socket lsocket;
  179.     struct socket *fsocket;
  180.     struct mbuf *packet;
  181.     int ckfail = 0;
  182.  
  183.     if(bp == NULLBUF)
  184.         return;
  185.  
  186.     udp_stat.rcvd++;
  187.  
  188.     /* Create pseudo-header and verify checksum */
  189.     ph.source = source;
  190.     ph.dest = dest;
  191.     ph.protocol = protocol;
  192.     ph.length = length;
  193.  
  194.     if(cksum(&ph,bp,length) != 0)
  195.         /* Checksum apparently failed, note for later */
  196.         ckfail++;
  197.  
  198.     /* Extract UDP header in host order */
  199.     ntohudp(&udp,&bp);
  200.  
  201.     /* If the checksum field is zero, then ignore a checksum error.
  202.      * I think this is dangerously wrong, but it is in the spec.
  203.      */
  204.     if(ckfail && udp.checksum != 0){
  205.         udp_stat.cksum++;
  206.         free_p(bp);
  207.         return;
  208.     }
  209.     /* If this was a broadcast packet, pretend it was sent to us */
  210.     if(rxbroadcast){
  211.         lsocket.address = ip_addr;
  212.         udp_stat.bdcsts++;
  213.     } else
  214.         lsocket.address = dest;
  215.  
  216.     lsocket.port = udp.dest;
  217.     /* See if there's somebody around to read it */
  218.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  219.         /* Nope, toss it on the floor */
  220.         udp_stat.unknown++;
  221.         free_p(bp);
  222.         return;
  223.     }
  224.     /* Create space for the foreign socket info */
  225.     if((packet = pushdown(bp,sizeof(struct socket))) == NULLBUF){
  226.         /* No space, drop whole packet */
  227.         free_p(bp);
  228.         return;
  229.     }
  230.     fsocket = (struct socket *)packet->data;
  231.     fsocket->address = source;
  232.     fsocket->port = udp.source;
  233.  
  234.     /* Queue it */
  235.     enqueue(&up->rcvq,packet);
  236.     up->rcvcnt++;
  237.     if(up->r_upcall)
  238.         (*up->r_upcall)(&lsocket,up->rcvcnt);
  239. }
  240. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  241. static
  242. struct udp_cb *
  243. lookup_udp(socket)
  244. struct socket *socket;
  245. {
  246.     register struct udp_cb *up;
  247.     int16 hash_udp();
  248.  
  249.     up = udps[hash_udp(socket)];
  250.     while(up != NULLUDP){
  251.         if(socket->port == up->socket.port
  252.          && (socket->address == up->socket.address
  253.          || up->socket.address == 0))
  254.             break;
  255.         up = up->next;
  256.     }
  257.     return up;
  258. }
  259.  
  260. /* Hash a UDP socket (address and port) structure */
  261. static
  262. int16
  263. hash_udp(socket)
  264. struct socket *socket;
  265. {
  266.     int16 hval;
  267.  
  268.     /* Compute hash function on socket structure */
  269. /*    hval = hiword(socket->address);
  270.     hval ^= loword(socket->address);
  271.     hval ^= socket->port;
  272. */
  273.     hval = socket->port;
  274.     hval %= NUDP;
  275.     return hval;
  276. }
  277. /* Convert UDP header in internal format to an mbuf in external format */
  278. struct mbuf *
  279. htonudp(udp,data,ph)
  280. struct udp *udp;
  281. struct mbuf *data;
  282. struct pseudo_header *ph;
  283. {
  284.     struct mbuf *bp;
  285.     register char *cp;
  286.     int16 checksum;
  287.  
  288.     /* Allocate UDP protocol header and fill it in */
  289.     if((bp = pushdown(data,UDPHDR)) == NULLBUF)
  290.         return NULLBUF;
  291.  
  292.     cp = bp->data;
  293.     cp = put16(cp,udp->source);    /* Source port */
  294.     cp = put16(cp,udp->dest);    /* Destination port */
  295.     cp = put16(cp,udp->length);    /* Length */
  296.     *cp++ = 0;            /* Clear checksum */
  297.     *cp-- = 0;
  298.  
  299.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  300.      * the spec requires us to change zeros into ones to distinguish an
  301.       * all-zero checksum from no checksum at all
  302.      */
  303.     if((checksum = cksum(ph,bp,ph->length)) == 0)
  304.         checksum = 0xffffffff;
  305.     put16(cp,checksum);
  306.     return bp;
  307. }
  308. /* Convert UDP header in mbuf to internal structure */
  309. ntohudp(udp,bpp)
  310. struct udp *udp;
  311. struct mbuf **bpp;
  312. {
  313.     udp->source = pull16(bpp);
  314.     udp->dest = pull16(bpp);
  315.     udp->length = pull16(bpp);
  316.     udp->checksum = pull16(bpp);
  317. }
  318.